package file

//annotation:File-service
//author:{"name":"File","tel":"18928776452","email":"XUnion@GMail.com"}

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sevlteServer/auto"
	"sevlteServer/tool"
	"strings"
	"time"
)

func Enroll(author string) {
	var developer *tool.ModuleAuthor
	if author != "" {
		var d tool.ModuleAuthor
		err := json.Unmarshal([]byte(author), &d)
		if err != nil {
			fmt.Println(err.Error())
			return
		}
		developer = &d
	}

	auto.AddService(&tool.ServeEndPoint{
		Fn: GetFile,

		Path: "/getfile",
		Name: "getfile",

		Developer: developer,
	})

	auto.AddService(&tool.ServeEndPoint{
		Fn:   DownloadFile,
		Path: "/downloadfile",
		Name: "downloadfile",

		Developer: developer,
	})

	auto.AddService(&tool.ServeEndPoint{
		Fn:   FileUpload,
		Path: "/fileupload",
		Name: "fileupload",

		Developer: developer,
	})

	auto.AddService(&tool.ServeEndPoint{
		Fn:   DelFile,
		Path: "/delfile",
		Name: "delfile",

		Developer: developer,
	})

	auto.AddService(&tool.ServeEndPoint{
		Fn:   ListFile,
		Path: "/listfile",
		Name: "listfile",

		Developer: developer,
	})
}

type FileInfo struct {
	Id       string     `json:"id"`
	Name     string     `json:"text"`
	Icon     string     `json:"icon"`
	Type     int        `json:"type"`
	Disabled bool       `json:"disabled"`
	Size     int64      `json:"size"`
	Mode     uint32     `json:"mode"`
	ModTime  time.Time  `json:"modtime"`
	Child    []FileInfo `json:"children"`
}
type replyFileInfo struct {
	Status int        `json:"status"`
	Files  []FileInfo `json:"files"`
}

func addfile(path string, files *[]FileInfo) {
	allitem, err := os.ReadDir(path)
	for _, i := range allitem {
		info, _ := i.Info()
		file := FileInfo{
			Id:       info.Name(),
			Name:     info.Name(),
			Type:     int(i.Type()),
			Disabled: false,
			Size:     info.Size(),
			Mode:     uint32(info.Mode()),
			ModTime:  info.ModTime(),
		}
		if info.IsDir() {
			//file.Child = make([]FileInfo, 0)
			file.Icon = "Folders"
			addfile(path+"/"+file.Name, &file.Child)
			*files = append(*files, file)
		} else {
			file.Icon = "DocumentDownload"
			*files = append(*files, file)
		}
	}
	if err != nil {
		fmt.Println(err.Error())
	}
}
func ListFile(r *http.Request, w http.ResponseWriter) {

	replyfiles := replyFileInfo{}
	root := "../file"

	addfile(root, &replyfiles.Files)

	buf, err := json.Marshal(&replyfiles)
	if err != nil {
		fmt.Println(err.Error())
		tool.Resp(w, &tool.ReplyProto{Status: -200})
		return
	}
	_, err = w.Write(buf)
	if err != nil {
		fmt.Println(err.Error())
		tool.Resp(w, &tool.ReplyProto{Status: -200})
		return
	}
}

func GetFile(r *http.Request, w http.ResponseWriter) {
	type Fileinfo struct {
		Name    string    `json:"name"`
		Size    int64     `json:"size"`
		Mode    uint32    `json:"mode"`
		ModTime time.Time `json:"modtime"`
	}
	type replyFileInfo struct {
		Status int        `json:"status"`
		Files  []Fileinfo `json:"files"`
	}
	replyfiles := replyFileInfo{}
	root := "../file"
	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		file := Fileinfo{
			Name:    info.Name(),
			Size:    info.Size(),
			Mode:    uint32(info.Mode()),
			ModTime: info.ModTime(),
		}
		if !info.IsDir() {
			replyfiles.Files = append(replyfiles.Files, file)
		}
		return nil
	})
	if err != nil {
		fmt.Println(err.Error())
	}

	buf, err := json.Marshal(&replyfiles)
	if err != nil {
		fmt.Println(err.Error())
		tool.Resp(w, &tool.ReplyProto{Status: -200})
		return
	}
	_, err = w.Write(buf)
	if err != nil {
		fmt.Println(err.Error())
		tool.Resp(w, &tool.ReplyProto{Status: -200})
		return
	}
}

func DownloadFile(r *http.Request, w http.ResponseWriter) {
	fmt.Println(r.RequestURI)
	//
	//fmt.Printf("download url=%s \n", r.RequestURI)
	//
	//fe := r.RequestURI[1:]
	//fmt.Println(fe)

	all, err := io.ReadAll(r.Body)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	jsonMap := make(map[string]interface{})
	err = json.Unmarshal(all, &jsonMap)

	fmt.Println("download url= ", jsonMap["file"])

	filename := jsonMap["file"].(string)
	enEscapeUrl, err := url.QueryUnescape(filename)
	if err != nil {
		fmt.Println(err.Error())
		_, err2 := w.Write([]byte(err.Error()))
		if err2 != nil {
			fmt.Println(err2.Error())
			return
		}
		return
	}

	f, err := os.Open("../file/" + enEscapeUrl)
	if err != nil {
		fmt.Println(err.Error())
		_, err := w.Write([]byte(err.Error()))
		if err != nil {
			fmt.Println(err.Error())
			return
		}
		return
	}

	//info, err := f.Stat()
	//if err != nil {
	//	fmt.Println(err.Error())
	//	_, err := w.Write([]byte(err.Error()))
	//	if err != nil {
	//		fmt.Println(err.Error())
	//		return
	//	}
	//	return
	//}
	//_, contentType := getContentType(filename)
	//w.Header().Set("Content-Disposition", "attachment; filename="+filename)
	////w.Header().Set("Content-Type", http.DetectContentType(fileHeader))
	//w.Header().Set("Content-Type", contentType)
	//w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))

	fileBytes, err := io.ReadAll(f)
	fmt.Println(fileBytes)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Write(fileBytes)
	//_, err = f.Seek(0, 0)
	//if err != nil {
	//	fmt.Println(err.Error())
	//	return
	//}
	//s, er := io.Copy(w, f)
	//fmt.Printf("copy: %s ", s)
	//if er != nil {
	//	fmt.Println(er.Error())
	//	return
	//}
}

func FileUpload(r *http.Request, w http.ResponseWriter) {
	contentType := r.Header.Get("content-type")
	contentLen := r.ContentLength

	fmt.Printf("upload content-type:%s,content-length:%d", contentType, contentLen)
	if !strings.Contains(contentType, "multipart/form-data") {
		fmt.Println("content-type must be multipart/form-data")
		w.Write([]byte("content-type must be multipart/form-data"))
		return
	}
	if contentLen >= 4*1024*1024 { // 10 MB
		fmt.Println("file to large,limit 4MB")
		w.Write([]byte("file to large,limit 4MB"))
		return
	}

	err := r.ParseMultipartForm(4 * 1024 * 1024)
	if err != nil {
		//http.Error(w, err.Error(), http.StatusInternalServerError)
		fmt.Println("ParseMultipartForm error:" + err.Error())
		w.Write([]byte("ParseMultipartForm error:" + err.Error()))
		return
	}

	if len(r.MultipartForm.File) == 0 {
		fmt.Println("not have any file")
		w.Write([]byte("not have any file"))
		return
	}

	for name, files := range r.MultipartForm.File {
		fmt.Printf("r.MultipartForm.File,name=%s", name)

		if len(files) != 1 {
			w.Write([]byte("too many files"))
			return
		}
		if name == "" {
			w.Write([]byte("is not FileData"))
			return
		}

		for _, f := range files {
			handle, err := f.Open()
			if err != nil {
				w.Write([]byte(fmt.Sprintf("unknown error,fileName=%s,fileSize=%d,err:%s", f.Filename, f.Size, err.Error())))
				return
			}

			path := "../file/" + f.Filename
			dst, err := os.Create(path)
			if err != nil {
				fmt.Println(err.Error())
				w.Write([]byte("create error"))
				return
			}
			_, err = io.Copy(dst, handle)
			if err != nil {
				fmt.Println(err.Error())
				w.Write([]byte("copy error"))
				return
			}
			dst.Close()
			fmt.Printf("successful uploaded,fileName=%s,fileSize=%.2f MB,savePath=%s \n", f.Filename, float64(contentLen)/1024/1024, path)

			tool.Resp(w, &tool.ReplyProto{Status: 0, Msg: "successful,url=" + url.QueryEscape(f.Filename)})
		}
	}

}

func DelFile(r *http.Request, w http.ResponseWriter) {
	body, err := io.ReadAll(r.Body)
	if err != nil {
		fmt.Println(err.Error())
		tool.Resp(w, &tool.ReplyProto{Status: -100})
		return
	}

	jsonMap := make(map[string]interface{})
	//将json字符串转换成map
	err = json.Unmarshal(body, &jsonMap)

	filename := "../file/" + jsonMap["file"].(string)
	err = os.Remove(filename)
	if err != nil {
		fmt.Println(err.Error())
		tool.Resp(w, &tool.ReplyProto{Status: -100})
		return
	}
	tool.Resp(w, &tool.ReplyProto{Status: 0})
}
